/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufrn.dca.controle;

/**
 * Classe reponsavel por realizar as ações de controle
 *
 * @author allan
 */
public class PID {

    /**
     * Erro entre o SP e a referencia
     */
    private double erro;
    /**
     * Erro anterior e(k-1)
     */
    private double erroAnt;
    /**
     * Ação integral anterior i(k-1)
     */
    private double iAnt;
    /**
     * Periodo de amostragem
     */
    private double h;
    /**
     * Ganho proporcional
     */
    private double kp;
    /**
     * Ganho integral
     */
    private double ki;
    /**
     * Ganho derivativo
     */
    private double kd;
    /**
     * Seleciona o tipo de controlador a ser usado
     */
    private tipoPID tipo;
    private double AcaoP;
    private double AcaoI;
    private double AcaoD;
    private double Acao_D;
    private double nivelAnt;

    public PID() {
        this.erro = 0;
        this.erroAnt = 0;
        this.kp = 0;
        this.ki = 0;
        this.kd = 0;
        this.h = 0.1;
        this.iAnt = 0;
        this.AcaoD = 0;
        this.AcaoI = 0;
        this.AcaoP = 0;
        this.Acao_D = 0;
        this.nivelAnt = 0;
    }
    
    public void reset(){
        this.erro = 0;
        this.erroAnt = 0;
        this.kp = 0;
        this.ki = 0;
        this.kd = 0;
        this.h = 0.1;
        this.iAnt = 0;
        this.AcaoD = 0;
        this.AcaoI = 0;
        this.AcaoP = 0;
        this.Acao_D = 0;
        this.nivelAnt = 0;
    }

    /**
     * Realiza o calculo da ação proporcional
     *
     * @return
     */
    public double acaoP() {
        AcaoP = kp * erro;
//        System.out.println("AcaoP " + AcaoP);
        return AcaoP;
    }

    /**
     * Realiza o calculo da ação integral
     *
     * @return
     */
    public double acaoI() {
        AcaoI = iAnt + ki * erro * h;
        iAnt = AcaoI;
//        System.out.println("AcaoI " + AcaoI);
        return AcaoI;
    }

    /**
     * Realiza o calculo da ação derivativa
     *
     * @return
     */
    public double acaoD() {
        AcaoD = kd * (erro - erroAnt) / h;
//        System.out.println("AcaoD " + AcaoD);
        return AcaoD;
    }
    
    public double acao_D(double nivel){
        AcaoD = kd* ((nivel/6.25) - (nivelAnt/6.25))/h;
        nivelAnt = nivel;
        return Acao_D;
    }

    /**
     * Realiza os travamentos adequado do sinal de saida e do nivel da planta
     *
     * @param saida saida do controlador
     * @param nivel nivel do tanque 1
     * @return
     */
    public double travamentos(double saida, double nivel) {

        double novaSaida = saida;

        if (novaSaida > 3) {
            novaSaida = 3;
        }
        if (novaSaida < -3) {
            novaSaida = -3;
        }
        if (nivel > 28) {
            novaSaida = Math.min(1.23, novaSaida);
            if (nivel > 30) {
                novaSaida = Math.min(0, novaSaida);
            }
        }
        if (nivel < 2) {
            novaSaida = Math.max(0, novaSaida);
        }
        return novaSaida;
    }

    /**
     * Calcula a ação de controle PID
     *
     * @param referencia referência
     * @param nivelT1 nivel tanque 1
     * @param nivelT2 nivel tanque 2
     * @return
     */
    public double controlePID(double referencia, double nivelT1, double nivelT2) {
        calculaErro(referencia, nivelT2);

        double saidaAux = acaoP() + acaoI() + acaoD();

        double saida = travamentos(saidaAux, nivelT1);
       
        return saida;
    }

    /**
     * Calcula o erro entre a referencia passada e o nivel do tanque
     *
     * @param ref
     * @param nivel
     */
    public void calculaErro(double ref, double nivel) {
        double ks = 6.25;
        erroAnt = erro;
        erro = (ref / ks) - (nivel / ks);

    }

    /**
     * Sintoniza os controladores de acordo com os parametros passados
     *
     * @param kp ganho estatico da planta
     * @param L delay da planta
     * @param T constante de tempo da planta
     * @param Ku ganho critico
     * @param Pu periodo critico
     */
    public void sintonizar(double kp, double L, double T, double Ku, double Pu) {
        if (tipo == tipoPID.COHENCOON) {
            cohenCoon cohencoon = new cohenCoon(kp, L, T);
            this.kp = cohencoon.Kp();
            this.ki = cohencoon.Ki();
            this.kd = cohencoon.Kd();
        }

        if (tipo == tipoPID.ZN) {
            ZN zn = new ZN(Ku, Pu);
            this.kp = zn.kp();
            this.ki = zn.ki();
            this.kd = zn.kd();
        }

        if (tipo == tipoPID.LR_2ORDEM) {
            LR lr2 = new LR();
            lr2.PID(T, L, kp);
            this.kp = lr2.getKp();
            this.ki = lr2.getKi();
            this.kd = lr2.getKd();
        }

        if (tipo == tipoPID.LR_1ORDEM) {
            LR lr1 = new LR();
            lr1.primeiraOrdem(T, L, kp);
            this.kp = lr1.getKp();
            this.ki = lr1.getKi();
            this.kd = lr1.getKd();
        }

    }

    public double getErro() {
        return erro;
    }

    public void setErro(double erro) {
        this.erro = erro;
    }

    public double getErroAnt() {
        return erroAnt;
    }

    public void setErroAnt(double erroAnt) {
        this.erroAnt = erroAnt;
    }

    public double getiAnt() {
        return iAnt;
    }

    public void setiAnt(double iAnt) {
        this.iAnt = iAnt;
    }

    public double getH() {
        return h;
    }

    public void setH(double h) {
        this.h = h;
    }

    public double getKp() {
        return kp;
    }

    public void setKp(double kp) {
        this.kp = kp;
    }

    public double getKi() {
        return ki;
    }

    public void setKi(double ki) {
        this.ki = ki;
    }

    public double getKd() {
        return kd;
    }

    public void setKd(double kd) {
        this.kd = kd;
    }

    public tipoPID getTipo() {
        return tipo;
    }

    public void setTipo(tipoPID tipo) {
        this.tipo = tipo;
    }
}
